package com.bckj.fastboot.core.extra.relational.configuration;

import com.bckj.fastboot.core.extra.relational.RelationalMappingContext;
import com.bckj.fastboot.core.extra.relational.RelationalOps;
import com.bckj.fastboot.core.util.SpringUtils;
import jakarta.persistence.Table;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.data.jdbc.repository.config.AbstractJdbcConfiguration;
import org.springframework.data.util.TypeScanner;
import org.springframework.jdbc.core.simple.JdbcClient;
import org.springframework.util.StringUtils;

import javax.sql.DataSource;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;

/**
 * JdbcConfiguration
 *
 * @author wfc
 **/
@AutoConfiguration
@ConditionalOnClass(Table.class)
@EnableConfigurationProperties(RelationalProperties.class)
public class RelationalConfiguration implements InitializingBean {

    protected Collection<String> getMappingBasePackages() {

        Package mappingBasePackage = getClass().getPackage();
        return Collections.singleton(mappingBasePackage == null ? null : mappingBasePackage.getName());
    }

    protected Set<Class<?>> getInitialEntitySet() {

        Set<Class<?>> initialEntitySet = new HashSet<>();

        for (String basePackage : getMappingBasePackages()) {
            initialEntitySet.addAll(scanForEntities(basePackage));
        }

        return initialEntitySet;
    }

    @SuppressWarnings("unchecked")
    protected Set<Class<?>> scanForEntities(String basePackage) {

        if (!StringUtils.hasText(basePackage)) {
            return Collections.emptySet();
        }

        return TypeScanner.typeScanner(AbstractJdbcConfiguration.class.getClassLoader())
                .forTypesAnnotatedWith(org.springframework.data.relational.core.mapping.Table.class)
                .scanPackages(basePackage)
                .collectAsSet();
    }

    @Bean
    public RelationalMappingContext relationalMappingContext() throws ClassNotFoundException {
        RelationalMappingContext mappingContext = new RelationalMappingContext();
        mappingContext.setInitialEntitySet(getInitialEntitySet());
        return mappingContext;
    }

    @Bean
    @ConditionalOnMissingBean(JdbcClient.class)
    @ConditionalOnBean(DataSource.class)
    public JdbcClient jdbcClient(DataSource dataSource) {
        return JdbcClient.create(dataSource);
    }

    @Bean
    public RelationalOps relationalOps(JdbcClient jdbcClient, RelationalMappingContext mappingContext) {
        return new RelationalOps(jdbcClient, mappingContext);
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        // 初始化全局配置
        RelationalProperties properties = SpringUtils.getBean(RelationalProperties.class);
        RelationalGlobalConfig.getInstance().config(properties);

    }
}
